/*
 * Copyright 2016-2022 NXP
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * o Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 *
 * o Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * o Neither the name of NXP Semiconductor, Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
/**
 * @file    LPC55S69_Project.cpp
 * @brief   Application entry point.
 */
#include <new>
#include "board.h"
#include "peripherals.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "LPC55S69_cm33_core0.h"
#include "fsl_debug_console.h"
#include <array>
//#include <exception>
//#include <iostream>

/* TODO: insert other include files here. */

/* TODO: insert other definitions and declarations here. */

/*
 * @brief   Application entry point.
 *
 */

#define BOARD_LED_PORT BOARD_LED_RED_GPIO_PORT
#define BOARD_LED_PIN  BOARD_LED_RED_GPIO_PIN

extern "C"
{
/*******************************************************************************
 * Variables
 ******************************************************************************/
volatile uint32_t g_systickCounter;

/*******************************************************************************
 * Code
 ******************************************************************************/
void SysTick_Handler(void)
{
    if (g_systickCounter != 0U)
    {
        g_systickCounter--;
    }
}

void SysTick_DelayTicks(uint32_t n)
{
    g_systickCounter = n;
    while (g_systickCounter != 0U)
    {
    }
}
}

class  GpioControlReg {
public:
	GpioControlReg(){
		//printf("do something");
	}
	enum class Port_t : uint8_t
	{
		PORT0,
		PORT1
	};
	enum class Level_t : uint8_t
	{
		LOW,
		HIGH
	};
	enum class Pin_t : uint8_t
	{
		PIN6 = 6,
		PIN9 = 9
	};

	inline void PortToggle(Port_t port, Pin_t pin)
	{
	    base.NOT[(uint32_t)port] = uint32_t(1u << (uint32_t)pin);
	}

	inline Level_t GPIO_PinRead(Port_t port, Pin_t pin)
	{
	    return (Level_t)base.B[(uint8_t)port][(uint8_t)pin];
	}

private:
	volatile GPIO_Type base;
};

class Led {
public:
	inline Led(GpioControlReg* cr, GpioControlReg::Port_t port, GpioControlReg::Pin_t pin) : 
        m_pcr(cr),
        m_port(port),
        m_pin(pin)
        {}

        inline void Toggle()
        {
           m_pcr->PortToggle(m_port, m_pin);
        }
        
private:
	GpioControlReg* const m_pcr;
	const GpioControlReg::Port_t m_port;
	const GpioControlReg::Pin_t m_pin;
};


class Key {
public:
	inline Key(GpioControlReg* cr, GpioControlReg::Port_t port, GpioControlReg::Pin_t pin) :
        m_pcr(cr),
        m_port(port),
        m_pin(pin)
        {}

        inline GpioControlReg::Level_t Read()
        {
           return m_pcr->GPIO_PinRead(m_port, m_pin);
        }
        
private:
	GpioControlReg* const m_pcr;
	const GpioControlReg::Port_t m_port;
	const GpioControlReg::Pin_t m_pin;
};

int main() {
    /* Init board hardware. */
    BOARD_InitBootPins();
    BOARD_InitBootClocks();
    BOARD_InitBootPeripherals();
#ifndef BOARD_INIT_DEBUG_CONSOLE_PERIPHERAL
    /* Init FSL debug console. */
    BOARD_InitDebugConsole();
#endif
    //setvbuf(stdout, NULL, _IONBF, 0);

    /* Set systick reload value to generate 1ms interrupt */
     if (SysTick_Config(SystemCoreClock / 1000U))
     {
         while (1)
         {
         }
     } 
     GpioControlReg* const pcr = new(reinterpret_cast<void*>(GPIO_BASE))GpioControlReg{};

     while (1)
     {
    	 using Port = GpioControlReg::Port_t;
    	 using Pin = GpioControlReg::Pin_t;
    	 using Level = GpioControlReg::Level_t;
         /* Delay 1000 ms */
         SysTick_DelayTicks(200U);

         Led led(pcr, Port::PORT1, Pin::PIN6);
         Key key(pcr, Port::PORT1, Pin::PIN9);
         if (key.Read() == Level::HIGH)
         {
        	// putchar('.');
        	 //GPIO_PortToggle(GPIO, BOARD_LED_PORT, 1u << BOARD_LED_PIN);
        	 led.Toggle();

         }
     }
}
